﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace HOSTRestarter
{
    class Program
    {
        const string BTS_WMI_CLASS = @"root\MicrosoftBizTalkServer";

        /// <summary>
        /// This is my quickly written, host stopper, I got sick of waiting for the hosts to restart from the admin console. 
        /// Writing this cost me 30 minutes, and saved me 60 minutes a day. 
        /// I provide the code and program for your pleasure. 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Console.WriteLine("BizTalk FASTER Host Restarter. (c) Paul Somers");
            if (args.Length < 1)
            {
                Console.WriteLine("USAGE: {0} [Method:{Start|Stop|Restart}]", System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
                return;
            }            

            string method = args[0];
            if (method != "Start" && method != "Stop" && method.ToLower()!="restart")
            {
                Console.WriteLine("Invalid Method {1}\n\nUSAGE: {0} [Method:Start,Stop,Restart]", System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName, method);
                return;
            }

            Console.WriteLine("{0} All Hosts", method);

            EnumerationOptions enumOptions = new EnumerationOptions();
            enumOptions.ReturnImmediately = false;
            //Search for all HostInstances of 'InProcess' type in the Biztalk namespace scope

            stopperstarter[] ststoppers = new stopperstarter[50];
            Thread[] trd = new Thread[50];
            ThreadStart[] trds = new ThreadStart[50];
         
            bool brestart = false;
            if (method.ToLower() == "restart")
            {
                brestart = true;
                method = "Stop";
            }
            bool bExit = false;
            while (!bExit)
            {
                int cntr = 0;

                ManagementObjectSearcher searchObject = new ManagementObjectSearcher("root\\MicrosoftBizTalkServer", "Select * from MSBTS_HostInstance where HostType=1", enumOptions);

                //Enumerate through the result set and the method on each HostInstance 
                foreach (ManagementObject inst in searchObject.Get())
                {
                    stopperstarter stsp = new stopperstarter();
                    stsp.inst = inst;
                    stsp.method = method;                    

                    //Just some nicer formatting
                    string hostname = inst["HostName"].ToString();
                    int gap = 30;
                    gap -= hostname.Length;
                    while (gap > 0)
                    {
                        hostname += " ";
                        gap--;
                    }

                    //Just some nicer formatting
                    string runningserver = inst["RunningServer"].ToString();
                    gap = 15;
                    gap -= runningserver.Length;
                    while (gap > 0)
                    {
                        runningserver += " ";
                        gap--;
                    }
                    //set up the thread object
                    stsp.host = hostname;
                    stsp.server = runningserver;
                    ststoppers[cntr] = stsp;
                    trds[cntr] = new ThreadStart(stsp.doit);
                    trd[cntr] = new Thread(trds[cntr]);
                    trd[cntr].Start();
                    cntr++;

                    Console.WriteLine("Host: {0} ON: {1} {2} Queued", hostname, runningserver, method);
                }
                bool finished = false;
                int done = 0;
                while (!finished)
                {
                    for (int t = 0; t < cntr; t++)
                    {
                        if (ststoppers[t].host != string.Empty)
                        {
                            //Check when the thread is finished, hence it's done it's job
                            if (trd[t].ThreadState == ThreadState.Stopped)
                            {
                                Console.WriteLine("Host: {0} ON: {1} {2} Done", ststoppers[t].host, ststoppers[t].server, method);
                                ststoppers[t].host = string.Empty;
                                done++;
                            }
                        }
                    }
                    if (done == cntr)
                    {
                        finished = true;
                    }
                    else
                    {
                        Thread.Sleep(new TimeSpan(0, 0, 3));
                    }
                }

                if (brestart)
                {
                    if (method == "Stop")
                    {
                        method = "Start";
                    }
                    else
                    {
                        bExit = true;
                    }
                }
                else
                {
                    bExit = true;
                }
            }
            Console.WriteLine("All Host Instances done");
        }

        /// <summary>
        /// Magic stoperstarter, it will apply the method set to the host 
        /// instance object, and then abort the current thread and die.
        /// </summary>
        private class stopperstarter
        {            
            public ManagementObject inst;
            public string method;
            public string host;
            public string server;

            public void doit()
            {
                inst.InvokeMethod(method, null);
                Thread.CurrentThread.Abort();
            }
        }
    }
}
